'----------------------------------------------
' Name: Ali Karbassi
'       Matt Latzke
'       Chris Hanegraaf
'       Brian Culp
' Date: May 1, 2007
' Description: Program 8
'              Module databaseModule
'----------------------------------------------
Imports System.Threading

Public Module databaseModule

   ' the user lawl
   Public user As ReaderWriter

   ' The data in database
   Public _total As Integer = 100

   ' To enforce the FIFO rule
   Public Q As New Queue

   ' To control data access reader/writer count
   Public RC As Integer
   Public WC As Integer
   Public DataObj As New Object

   ' Database manager
   Public manager As Thread
   Public managerDone As Boolean = False
   Public managerEvent As New AutoResetEvent(False)

   ' To terminate the manager gracefully when to terminate the program
   Private endProgram As New ManualResetEvent(False)

   ''' <summary>
   ''' Spins up
   ''' </summary>
   ''' <remarks></remarks>
   Public Sub spinUp()
      manager = New Thread(AddressOf run)
      manager.Start()
   End Sub

   ''' <summary>
   ''' Finishes the read/write.
   ''' </summary>
   ''' <remarks></remarks>
   Public Sub FinishReadWrite()
      endProgram.Reset()
      managerEvent.Set()
      endProgram.WaitOne()
   End Sub

   ''' <summary>
   ''' Handles the end manager.
   ''' </summary>
   ''' <remarks></remarks>
   Public Sub endManager()
      managerDone = True
      managerEvent.Set()
      manager.Join()
   End Sub

   ''' <summary>
   ''' Runs the main part
   ''' </summary>
   ''' <remarks></remarks>
   Public Sub run()

      managerEvent.Reset()
      managerEvent.WaitOne()

      While managerDone = False

         Monitor.Enter(DataObj)
         Monitor.Enter(Q)

         If Q.Count > 0 Then

            If RC > 0 Then

               user = CType(Q.Peek, ReaderWriter)

               If user.type = ReaderWriterType.Reader Then

                  user = CType(Q.Dequeue, ReaderWriter)
                  user.WakeUp()

               End If

            ElseIf WC = 0 Then

               user = CType(Q.Peek, ReaderWriter)

               If user.type = ReaderWriterType.Writer Then

                  user = CType(Q.Dequeue, ReaderWriter)
                  user.WakeUp()

               Else

                  While user.type = ReaderWriterType.Reader And Q.Count > 0

                     user = CType(Q.Dequeue, ReaderWriter)
                     user.WakeUp()

                     If Q.Count > 0 Then
                        user = CType(Q.Peek, ReaderWriter)
                     End If

                  End While
               End If
            End If
         End If

         Monitor.Exit(Q)
         Monitor.Exit(DataObj)
         managerEvent.Reset()
         managerEvent.WaitOne()

         If Q.Count = 0 And WC = 0 And RC = 0 Then
            endProgram.Set()
         End If

      End While

   End Sub
End Module
